/**
 * 工具函数库
 */

/**
 * 防抖函数
 * @param {Function} func - 要防抖的函数
 * @param {number} wait - 等待时间
 * @param {boolean} immediate - 是否立即执行
 * @returns {Function}
 */
export function debounce(func, wait, immediate) {
  let timeout
  return function executedFunction(...args) {
    const later = () => {
      timeout = null
      if (!immediate) func.apply(this, args)
    }
    const callNow = immediate && !timeout
    clearTimeout(timeout)
    timeout = setTimeout(later, wait)
    if (callNow) func.apply(this, args)
  }
}

/**
 * 节流函数
 * @param {Function} func - 要节流的函数
 * @param {number} limit - 时间间隔
 * @returns {Function}
 */
export function throttle(func, limit) {
  let inThrottle
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args)
      inThrottle = true
      setTimeout(() => inThrottle = false, limit)
    }
  }
}

/**
 * 深拷贝
 * @param {any} obj - 要拷贝的对象
 * @returns {any}
 */
export function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj
  if (obj instanceof Date) return new Date(obj.getTime())
  if (obj instanceof Array) return obj.map(item => deepClone(item))
  if (typeof obj === 'object') {
    const clonedObj = {}
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        clonedObj[key] = deepClone(obj[key])
      }
    }
    return clonedObj
  }
}

/**
 * 格式化文件大小
 * @param {number} bytes - 字节数
 * @param {number} decimals - 小数位数
 * @returns {string}
 */
export function formatFileSize(bytes, decimals = 2) {
  if (bytes === 0) return '0 Bytes'
  const k = 1024
  const dm = decimals < 0 ? 0 : decimals
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
}

/**
 * 格式化数字
 * @param {number} num - 数字
 * @returns {string}
 */
export function formatNumber(num) {
  if (num >= 1000000) {
    return (num / 1000000).toFixed(1) + 'M'
  } else if (num >= 1000) {
    return (num / 1000).toFixed(1) + 'K'
  }
  return num.toString()
}

/**
 * 格式化时间
 * @param {Date|string|number} date - 日期
 * @param {string} format - 格式
 * @returns {string}
 */
export function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
  const d = new Date(date)
  const year = d.getFullYear()
  const month = String(d.getMonth() + 1).padStart(2, '0')
  const day = String(d.getDate()).padStart(2, '0')
  const hours = String(d.getHours()).padStart(2, '0')
  const minutes = String(d.getMinutes()).padStart(2, '0')
  const seconds = String(d.getSeconds()).padStart(2, '0')

  return format
    .replace('YYYY', year)
    .replace('MM', month)
    .replace('DD', day)
    .replace('HH', hours)
    .replace('mm', minutes)
    .replace('ss', seconds)
}

/**
 * 相对时间格式化
 * @param {Date|string|number} date - 日期
 * @returns {string}
 */
export function formatRelativeTime(date) {
  const now = new Date()
  const target = new Date(date)
  const diff = now - target
  const seconds = Math.floor(diff / 1000)
  const minutes = Math.floor(seconds / 60)
  const hours = Math.floor(minutes / 60)
  const days = Math.floor(hours / 24)
  const months = Math.floor(days / 30)
  const years = Math.floor(months / 12)

  if (years > 0) return `${years}年前`
  if (months > 0) return `${months}个月前`
  if (days > 0) return `${days}天前`
  if (hours > 0) return `${hours}小时前`
  if (minutes > 0) return `${minutes}分钟前`
  return '刚刚'
}

/**
 * 格式化时长
 * @param {number} seconds - 秒数
 * @returns {string}
 */
export function formatDuration(seconds) {
  const hours = Math.floor(seconds / 3600)
  const minutes = Math.floor((seconds % 3600) / 60)
  const secs = seconds % 60

  if (hours > 0) {
    return `${hours}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`
  }
  return `${minutes}:${String(secs).padStart(2, '0')}`
}

/**
 * 生成随机字符串
 * @param {number} length - 长度
 * @returns {string}
 */
export function generateRandomString(length = 8) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let result = ''
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length))
  }
  return result
}

/**
 * 生成UUID
 * @returns {string}
 */
export function generateUUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0
    const v = c === 'x' ? r : (r & 0x3 | 0x8)
    return v.toString(16)
  })
}

/**
 * 验证邮箱
 * @param {string} email - 邮箱
 * @returns {boolean}
 */
export function validateEmail(email) {
  const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  return re.test(email)
}

/**
 * 验证手机号
 * @param {string} phone - 手机号
 * @returns {boolean}
 */
export function validatePhone(phone) {
  const re = /^1[3-9]\d{9}$/
  return re.test(phone)
}

/**
 * 验证身份证号
 * @param {string} idCard - 身份证号
 * @returns {boolean}
 */
export function validateIdCard(idCard) {
  const re = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
  return re.test(idCard)
}

/**
 * 验证密码强度
 * @param {string} password - 密码
 * @returns {Object}
 */
export function validatePasswordStrength(password) {
  const result = {
    score: 0,
    level: 'weak',
    suggestions: []
  }

  if (password.length < 8) {
    result.suggestions.push('密码长度至少8位')
  } else {
    result.score += 1
  }

  if (/[a-z]/.test(password)) {
    result.score += 1
  } else {
    result.suggestions.push('包含小写字母')
  }

  if (/[A-Z]/.test(password)) {
    result.score += 1
  } else {
    result.suggestions.push('包含大写字母')
  }

  if (/\d/.test(password)) {
    result.score += 1
  } else {
    result.suggestions.push('包含数字')
  }

  if (/[^\w\s]/.test(password)) {
    result.score += 1
  } else {
    result.suggestions.push('包含特殊字符')
  }

  if (result.score >= 4) {
    result.level = 'strong'
  } else if (result.score >= 2) {
    result.level = 'medium'
  }

  return result
}

/**
 * 获取URL参数
 * @param {string} name - 参数名
 * @param {string} url - URL
 * @returns {string|null}
 */
export function getUrlParam(name, url = window.location.href) {
  const regex = new RegExp('[?&]' + name + '=([^&#]*)', 'i')
  const match = regex.exec(url)
  return match ? decodeURIComponent(match[1]) : null
}

/**
 * 设置URL参数
 * @param {string} name - 参数名
 * @param {string} value - 参数值
 * @param {string} url - URL
 * @returns {string}
 */
export function setUrlParam(name, value, url = window.location.href) {
  const regex = new RegExp('([?&])' + name + '=.*?(&|$)', 'i')
  const separator = url.indexOf('?') !== -1 ? '&' : '?'
  
  if (url.match(regex)) {
    return url.replace(regex, '$1' + name + '=' + encodeURIComponent(value) + '$2')
  } else {
    return url + separator + name + '=' + encodeURIComponent(value)
  }
}

/**
 * 移除URL参数
 * @param {string} name - 参数名
 * @param {string} url - URL
 * @returns {string}
 */
export function removeUrlParam(name, url = window.location.href) {
  const regex = new RegExp('[?&]' + name + '=([^&#]*)', 'i')
  return url.replace(regex, '')
}

/**
 * 滚动到元素
 * @param {string|Element} element - 元素或选择器
 * @param {Object} options - 选项
 */
export function scrollToElement(element, options = {}) {
  const el = typeof element === 'string' ? document.querySelector(element) : element
  if (el) {
    el.scrollIntoView({
      behavior: 'smooth',
      block: 'start',
      ...options
    })
  }
}

/**
 * 滚动到顶部
 * @param {number} duration - 动画时长
 */
export function scrollToTop(duration = 300) {
  const start = window.pageYOffset
  const startTime = performance.now()

  function scroll() {
    const now = performance.now()
    const time = Math.min(1, (now - startTime) / duration)
    const timeFunction = 1 - Math.pow(1 - time, 3)
    window.scroll(0, Math.ceil((1 - timeFunction) * start))

    if (time < 1) {
      requestAnimationFrame(scroll)
    }
  }

  requestAnimationFrame(scroll)
}

/**
 * 复制到剪贴板
 * @param {string} text - 要复制的文本
 * @returns {Promise}
 */
export function copyToClipboard(text) {
  if (navigator.clipboard) {
    return navigator.clipboard.writeText(text)
  } else {
    return new Promise((resolve, reject) => {
      const textArea = document.createElement('textarea')
      textArea.value = text
      textArea.style.position = 'fixed'
      textArea.style.left = '-999999px'
      textArea.style.top = '-999999px'
      document.body.appendChild(textArea)
      textArea.focus()
      textArea.select()
      
      try {
        document.execCommand('copy')
        textArea.remove()
        resolve()
      } catch (err) {
        textArea.remove()
        reject(err)
      }
    })
  }
}

/**
 * 下载文件
 * @param {string} url - 文件URL
 * @param {string} filename - 文件名
 */
export function downloadFile(url, filename) {
  const link = document.createElement('a')
  link.href = url
  link.download = filename
  link.style.display = 'none'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}

/**
 * 获取设备类型
 * @returns {string}
 */
export function getDeviceType() {
  const ua = navigator.userAgent
  if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {
    return 'tablet'
  }
  if (/Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {
    return 'mobile'
  }
  return 'desktop'
}

/**
 * 获取浏览器信息
 * @returns {Object}
 */
export function getBrowserInfo() {
  const ua = navigator.userAgent
  let browser = 'Unknown'
  let version = 'Unknown'

  if (ua.indexOf('Chrome') > -1) {
    browser = 'Chrome'
    version = ua.match(/Chrome\/(\d+)/)[1]
  } else if (ua.indexOf('Firefox') > -1) {
    browser = 'Firefox'
    version = ua.match(/Firefox\/(\d+)/)[1]
  } else if (ua.indexOf('Safari') > -1) {
    browser = 'Safari'
    version = ua.match(/Version\/(\d+)/)[1]
  } else if (ua.indexOf('Edge') > -1) {
    browser = 'Edge'
    version = ua.match(/Edge\/(\d+)/)[1]
  }

  return { browser, version }
}

/**
 * 本地存储封装
 */
export const storage = {
  set(key, value, expire) {
    const data = {
      value,
      expire: expire ? Date.now() + expire * 1000 : null
    }
    localStorage.setItem(key, JSON.stringify(data))
  },

  get(key) {
    const item = localStorage.getItem(key)
    if (!item) return null

    try {
      const data = JSON.parse(item)
      if (data.expire && Date.now() > data.expire) {
        localStorage.removeItem(key)
        return null
      }
      return data.value
    } catch (e) {
      return null
    }
  },

  remove(key) {
    localStorage.removeItem(key)
  },

  clear() {
    localStorage.clear()
  }
}

/**
 * 会话存储封装
 */
export const sessionStorage = {
  set(key, value) {
    window.sessionStorage.setItem(key, JSON.stringify(value))
  },

  get(key) {
    const item = window.sessionStorage.getItem(key)
    try {
      return item ? JSON.parse(item) : null
    } catch (e) {
      return null
    }
  },

  remove(key) {
    window.sessionStorage.removeItem(key)
  },

  clear() {
    window.sessionStorage.clear()
  }
}

/**
 * 事件总线
 */
class EventBus {
  constructor() {
    this.events = {}
  }

  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = []
    }
    this.events[event].push(callback)
  }

  off(event, callback) {
    if (this.events[event]) {
      this.events[event] = this.events[event].filter(cb => cb !== callback)
    }
  }

  emit(event, ...args) {
    if (this.events[event]) {
      this.events[event].forEach(callback => callback(...args))
    }
  }

  once(event, callback) {
    const onceCallback = (...args) => {
      callback(...args)
      this.off(event, onceCallback)
    }
    this.on(event, onceCallback)
  }
}

export const eventBus = new EventBus()

/**
 * 图片懒加载
 * @param {string} selector - 图片选择器
 * @param {Object} options - 选项
 */
export function lazyLoadImages(selector = 'img[data-src]', options = {}) {
  const images = document.querySelectorAll(selector)
  const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target
        img.src = img.dataset.src
        img.classList.remove('lazy')
        imageObserver.unobserve(img)
      }
    })
  }, options)

  images.forEach(img => imageObserver.observe(img))
}

/**
 * 数组去重
 * @param {Array} arr - 数组
 * @param {string} key - 对象数组的唯一键
 * @returns {Array}
 */
export function uniqueArray(arr, key) {
  if (key) {
    const seen = new Set()
    return arr.filter(item => {
      const val = item[key]
      if (seen.has(val)) {
        return false
      }
      seen.add(val)
      return true
    })
  }
  return [...new Set(arr)]
}

/**
 * 数组分组
 * @param {Array} arr - 数组
 * @param {string|Function} key - 分组键或函数
 * @returns {Object}
 */
export function groupBy(arr, key) {
  return arr.reduce((groups, item) => {
    const group = typeof key === 'function' ? key(item) : item[key]
    groups[group] = groups[group] || []
    groups[group].push(item)
    return groups
  }, {})
}

/**
 * 数组排序
 * @param {Array} arr - 数组
 * @param {string} key - 排序键
 * @param {string} order - 排序方向 (asc|desc)
 * @returns {Array}
 */
export function sortArray(arr, key, order = 'asc') {
  return arr.sort((a, b) => {
    const aVal = typeof key === 'function' ? key(a) : a[key]
    const bVal = typeof key === 'function' ? key(b) : b[key]
    
    if (order === 'desc') {
      return bVal > aVal ? 1 : -1
    }
    return aVal > bVal ? 1 : -1
  })
}

/**
 * 树形数据扁平化
 * @param {Array} tree - 树形数据
 * @param {string} childrenKey - 子节点键名
 * @returns {Array}
 */
export function flattenTree(tree, childrenKey = 'children') {
  const result = []
  
  function traverse(nodes, parent = null) {
    nodes.forEach(node => {
      const item = { ...node, parent }
      delete item[childrenKey]
      result.push(item)
      
      if (node[childrenKey] && node[childrenKey].length > 0) {
        traverse(node[childrenKey], node)
      }
    })
  }
  
  traverse(tree)
  return result
}

/**
 * 扁平数据转树形
 * @param {Array} list - 扁平数据
 * @param {string} idKey - ID键名
 * @param {string} parentKey - 父ID键名
 * @param {string} childrenKey - 子节点键名
 * @returns {Array}
 */
export function listToTree(list, idKey = 'id', parentKey = 'parentId', childrenKey = 'children') {
  const map = {}
  const roots = []
  
  // 创建映射
  list.forEach(item => {
    map[item[idKey]] = { ...item, [childrenKey]: [] }
  })
  
  // 构建树形结构
  list.forEach(item => {
    const node = map[item[idKey]]
    if (item[parentKey] && map[item[parentKey]]) {
      map[item[parentKey]][childrenKey].push(node)
    } else {
      roots.push(node)
    }
  })
  
  return roots
}